﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Autofac;
using Autofac.Integration.Web;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NMock2;
using Vowei.Core.Models;
using Vowei.Web;
using Vowei.Data.Converters.Excel;
using Vowei.Data.Helpers;
using Vowei.Data.Models;
using Vowei.Data;

namespace vowei.test
{  
    /// <summary>
    ///This is a test class for DataLayerTest and is intended
    ///to contain all DataLayerTest Unit Tests
    ///</summary>
    [TestClass()]
    public class EntityHelpersTest : TestBase
    {
        [TestMethod()]
        public void FindTableByTypeTest()
        {
            using (var impl = new VoweiContextImpl())
            {
                Assert.IsNotNull(impl.FindTableByType<Milestone>());
                Assert.IsNotNull(impl.FindTableByType<Project>());
                Assert.IsNotNull(impl.FindTableByType<Ticket>());
                Assert.IsNotNull(impl.FindTableByType<Task>());
                Assert.IsNotNull(impl.FindTableByType<Requirement>());
            }
        }

        /// <summary>
        ///A test for Active
        ///</summary>
        public void ActiveTestHelper<T>()
            where T : class, ISupportDefaultProperties
        {
            using (var impl = new VoweiContextImpl())
            {
                IQueryable<T> table = impl.FindTableByType<T>();
                IQueryable<T> actual = table.Active<T>();

                Assert.IsTrue(actual.All(r => !r.ClosedDate.HasValue));
            }
        }

        [TestMethod()]
        public void ActiveTest()
        {
            ActiveTestHelper<Project>();
            ActiveTestHelper<Milestone>();
            ActiveTestHelper<Task>();
            ActiveTestHelper<Ticket>();
            ActiveTestHelper<Bug>();
        }
        
        public void ClosedTestHelper<T>()
            where T : class, ISupportDefaultProperties
        {
            using (var impl = new VoweiContextImpl())
            {
                var table = impl.FindTableByType<T>();
                var actual = EntityHelpers.Closed<T>(table);

                Assert.IsTrue(actual.All(r => r.ClosedDate != null &&
                                              r.ClosedDate < DateTime.Now));
            }
        }

        [TestMethod()]
        public void ClosedTest()
        {
            ClosedTestHelper<Project>();
            ClosedTestHelper<Milestone>();
            ClosedTestHelper<Task>();
            ClosedTestHelper<Ticket>();
            ClosedTestHelper<Bug>();
        }

        /// <summary>
        ///A test for Find
        ///</summary>
        public void FindTestHelper<T>()
            where T : class, INamedTable
        {
            using (var impl = new VoweiContextImpl())
            {
                var table = impl.FindTableByType<T>();
                var expected = table.First();
                var actual = impl.Find<T>(expected.ID);

                Assert.AreEqual(expected, actual);
                Assert.AreEqual(expected.ID, actual.ID);
                Assert.AreEqual(expected.Title, actual.Title);
            }
        }

        [TestMethod()]
        public void FindTest()
        {
            FindTestHelper<Project>();
            FindTestHelper<Milestone>();
            FindTestHelper<Ticket>();
            FindTestHelper<Task>();
            FindTestHelper<Requirement>();
        }

        /// <summary>
        ///A test for My
        ///</summary>
        [TestMethod()]
        public void MyTest()
        {
            MyTestHelper<Task>();
            MyTestHelper<Ticket>();
            MyTestHelper<Bug>();
            //MyTestHelper<MeetingRequest>();       
        }

        /// <summary>
        ///A test for My
        ///</summary>
        public void MyTestHelper<T>()
            where T : Ticket
        {
            var mocks = new Mockery();
            var user = mocks.NewMock<IUser>();
            var builder = new ContainerBuilder();
            builder.RegisterInstance(user).As<IUser>();

            var container = builder.Build();
            MvcApplication.ContainerProviderStatic = new ContainerProvider(container);

            try
            {
                var context = new VoweiContext(new VoweiContextImpl());
                var table = context.Resolve<T>();
                Expect.AtLeastOnce.On(user).Method("GetIdentifier").Will(Return.Value(Setting.DefaultUserName));
                var actual = table.Query.My(user).ToArray();

                Assert.IsTrue(actual.All(r => string.CompareOrdinal(r.AssignedTo,
                    Setting.DefaultUserName) == 0));
            }
            finally
            {
                MvcApplication.ContainerProviderStatic = null;
            }
        }

        [TestMethod]
        public void MyActiveTest()
        {
            MyActiveTestHelper<Task>();
            MyActiveTestHelper<Ticket>();
            MyActiveTestHelper<Bug>();
            //MyActiveTestHelper<MeetingRequest>();       
        }

        public void MyActiveTestHelper<T>()
            where T : Ticket
        {
            var mocks = new Mockery();
            var user = mocks.NewMock<IUser>();
            var builder = new ContainerBuilder();
            builder.RegisterInstance(user).As<IUser>();

            var container = builder.Build();
            MvcApplication.ContainerProviderStatic = new ContainerProvider(container);

            try
            {
                using (var impl = new VoweiContextImpl())
                {
                    var table = impl.FindTableByType<T>();
                    Expect.Once.On(user).GetProperty("Email").Will(Return.Value(Setting.DefaultUserName));
                    var actual = table.My(Setting.DefaultFormUser).Active();

                    Assert.IsTrue(actual.All(r => (r.AssignedTo == Setting.DefaultUserName) &&
                                                 !r.ClosedDate.HasValue));
                }
            }
            finally
            {
                MvcApplication.ContainerProviderStatic = null;
            }
        }

        [TestMethod]
        public void ActiveCloseTest()
        {
            ActiveCloseTestHelper<Project>();
            ActiveCloseTestHelper<Milestone>();
            ActiveCloseTestHelper<Task>();
            ActiveCloseTestHelper<Ticket>();
            ActiveCloseTestHelper<Bug>();
        }

        public void ActiveCloseTestHelper<T>()
            where T : class, ISupportDefaultProperties
        {
            using (var impl = new VoweiContextImpl())
            {
                var table = impl.FindTableByType<T>();
                var actual = table.Active().Closed();

                Assert.AreEqual(0, actual.Count());
            }
        }

        [TestMethod]
        public void TopTest()
        {
            TopTestHelper<Task>();
            TopTestHelper<Ticket>();
            TopTestHelper<Bug>();
            //TopTestHelper<MeetingRequest>();       
        }

        public void TopTestHelper<T>()
            where T : class , ISupportDefaultProperties
        {
            using (var impl = new VoweiContextImpl())
            {
                var table = impl.FindTableByType<T>();
                var queryCount = 10;
                var expected = Math.Min(queryCount, table.Count());

                var actual = table.Top(queryCount);
                Assert.AreEqual(expected, actual.Count());
            }
        }

        [TestMethod]
        public void UnAssignedRequirementsBasicTest()
        {
            var testName = "UnAssignedRequirementsBasicTest";
            var project = CreateProjectHelper(testName);
            var milestone = CreateMilestoneHelper(testName);
            var expected = new List<Requirement>();

            using (var impl = new VoweiContextImpl())
            {
                project.Children.Add(milestone);
                impl.Projects.Add(project);
                impl.Milestones.Add(milestone);

                expected.Add(CreateRequirementHelper(testName, milestone));
                expected.Add(CreateRequirementHelper(testName, project));

                foreach (var req in expected)
                    impl.Requirements.Add(req);

                impl.SaveChanges();
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var reqs = project.TopRequirements(context);
                var actual = new List<Requirement>();

                foreach (var req in reqs)
                    actual.Add((Requirement)req);

                Assert.AreEqual(expected.Count, actual.Count);

                for (int i = 0; i < expected.Count; ++i)
                {
                    Assert.IsTrue(actual.Any(a => expected[i].ID == a.ID));
                }
            }
        }

        [TestMethod]
        public void TopRequirementsFromControllerBasicTest()
        {
            var filename = Path.Combine(
                TestContext.TestDeploymentDir, @"StatisticsHelpersTest_TopRequirementWorksBasicTest.xls");
            var project = CreateProjectHelper("UnAssignedRequirementsFromControllerBasicTest");
            var projectId = project.ID;

            using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read))
            {
                var converter = new WorkItemExcelConverter(VoweiContext.TicketStatusManager);
                converter.WorkSheetName = "TaskSchedule";
                var works = converter.ConvertFrom(stream);

                using (var impl = new VoweiContextImpl())
                {
                    var context = new VoweiContext(impl);
                    impl.Projects.Add(project);
                    impl.SaveChanges();

                    ImportHelper.ImportDataTo(project, context, works, Setting.DefaultFormUser);
                    impl.SaveChanges();
                }
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                project = impl.Projects.Find(projectId);
                var reqs = project.TopRequirements(context);

                Assert.AreEqual(24, reqs.Count());
            }
        }
        
        [TestMethod]
        public void UnAssignedTasksBasicTest()
        {
            var testName = "UnAssignedTasksBasicTest";
            var project = CreateProjectHelper(testName);
            var milestone = CreateMilestoneHelper(testName);
            var expected = new List<Task>();

            using (var impl = new VoweiContextImpl())
            {
                project.Children.Add(milestone);
                impl.Projects.Add(project);
                impl.Milestones.Add(milestone);
                var requirement = CreateRequirementHelper(testName, milestone);

                expected.Add(CreateTaskHelper("UnAssignedTasksBasicTest1", project));
                expected.Add(CreateTaskHelper("UnAssignedTasksBasicTest2", milestone));
                expected.Add(CreateTaskHelper("UnAssignedTasksBasicTest3", milestone));
                requirement.Children.Add(expected[expected.Count - 1]);

                impl.Requirements.Add(requirement);

                foreach (var task in expected)
                    impl.Tasks.Add(task);

                impl.SaveChanges();
            }

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var tasks = project.UnAssignedTasks(context);
                var actual = new List<Task>();

                foreach (var task in tasks)
                    actual.Add((Task)task);

                Assert.AreEqual(2, actual.Count);

                for (int i = 0; i < expected.Count - 1; ++i)
                {
                    Assert.IsTrue(actual.Any(a => expected[i].ID == a.ID));
                }
            }
        }

        [TestMethod]
        public void UnAssignedTasksFromControllerBasicTest()
        {
            var project = GetStatisticsProject();

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                project = impl.Projects.Find(project.ID);
                var tasks = project.UnAssignedTasks(context);

                Assert.AreEqual(0, tasks.Count());
            }
        }

        private Project GetStatisticsProject()
        {
            var filename = Path.Combine(
                TestContext.TestDeploymentDir, @"StatisticsHelpersTest_TopRequirementWorksBasicTest.xls");

            using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read))
            {
                var converter = new WorkItemExcelConverter(VoweiContext.TicketStatusManager);
                var works = converter.ConvertFrom(stream);

                using (var impl = new VoweiContextImpl())
                {
                    if (impl.Projects.Any(p => p.Title == "EntityHelpersTest"))
                        return impl.Projects.Single(p => p.Title == "EntityHelpersTest");

                    var context = new VoweiContext(impl);
                    var project = new Project()
                    {
                        Title = "EntityHelpersTest",
                        Owner = Setting.DefaultUserName
                    };
                    impl.Projects.Add(project);
                    impl.SaveChanges();

                    ImportHelper.ImportDataTo(project, context, works, Setting.DefaultFormUser);
                    impl.SaveChanges();

                    return project;
                }
            }
        }

        [TestMethod]
        public void SearchByChangedTimeCriteriaTest()
        {
            var filename = Path.Combine(
                TestContext.TestDeploymentDir, @"StatisticsHelpersTest_TopRequirementWorksBasicTest.xls");
            var project = CreateProjectHelper("SearchByChangedTimeCriteriaTest");

            using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read))
            {
                var converter = new WorkItemExcelConverter(VoweiContext.TicketStatusManager);
                var works = converter.ConvertFrom(stream);

                using (var impl = new VoweiContextImpl())
                {
                    var context = new VoweiContext(impl);
                    impl.Projects.Add(project);
                    impl.SaveChanges();

                    ImportHelper.ImportDataTo(project, context, works, Setting.DefaultFormUser);
                    impl.SaveChanges();
                }
            }

            var criteria = new FilterCriteria()
            {
                ChangedAfter = DateTime.Now.Date - TimeSpan.FromDays(1)
            };

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var actual = project.AllTasks(context).Search(criteria);
                Assert.AreEqual(96, actual.Count());
                Assert.IsTrue(actual.Any(t => t.Title == "实现review工作流"));
            }
        }

        [TestMethod]
        public void SearchByUserNameCriteriaTest()
        {
            var project = GetStatisticsProject();

            var criteria = new FilterCriteria()
            {
                User = new Employee { Email = "yimin_shi@hotmail.com" }
            };

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var actual = project.AllTasks(context).Search(criteria);
                Assert.AreEqual(32, actual.Count());
                Assert.IsTrue(actual.Any(t => t.Title == "实现Bug的增改页面"));
            }
        }

        [TestMethod]
        public void SearchByUserNameActiveCriteriaTest()
        {
            var project = GetStatisticsProject();

            var criteria = new FilterCriteria()
            {
                User = new Employee { Email = "yimin_shi@hotmail.com" },
                IsActive = true
            };

            using (var impl = new VoweiContextImpl())
            {
                var context = new VoweiContext(impl);
                var actual = project.AllTasks(context).Search(criteria);
                Assert.AreEqual(24, actual.Count());
                Assert.IsFalse(actual.Any(t => t.ClosedDate.HasValue));
                Assert.IsTrue(actual.Any(t => t.Title == "实现Bug的增改页面"));
            }
        }
    }
}
